﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Automation;
using System.Windows.Automation.Text;
using QuickUIT.Input;

namespace QuickUIT.Controls
{
    /// <summary>
    /// Represents a generic control to be automated.  
    /// </summary>
    public abstract class UIBaseControl
    {
        private AutomationElement _control;
        private UIBaseControl _parentControl;
        private UIWindow _parentWindow;
        private readonly IAutomationElementSearchCriteria _searchCriteria; 

        /// <summary>
        /// The underlying <see cref="AutomationElement"/> for this control.  
        /// </summary>
        public AutomationElement Control
        {
            get { return _control; }
        }

        /// <summary>
        /// Gets the parent control.  
        /// </summary>
        public UIBaseControl ParentControl
        {
            get { return _parentControl; }
        }

        /// <summary>
        /// The parent window of the control. 
        /// </summary>
        public UIWindow ParentWindow
        {
            get { return _parentWindow; }
        }

        #region Basic Automation Properties
        
        /// <summary>
        /// Gets the automation identifier of the control.
        /// </summary>
        public string AutomationId
        {
            get { return Control.Current.AutomationId; }
        }

        /// <summary>
        /// Gets the name of the control.  
        /// </summary>
        public string Name
        {
            get { return Control.Current.Name; }
        }

        /// <summary>
        /// Indicates whether the control is enabled.  
        /// </summary>
        public bool IsEnabled
        {
            get { return Control.Current.IsEnabled; }
        }

        /// <summary>
        /// Indcates whether a control has keyboard focus.
        /// </summary>
        public bool HasKeyboardFocus
        {
            get { return Control.Current.HasKeyboardFocus; }
        }

        /// <summary>
        /// Returns the <see cref="ControlType"/> for this control.
        /// </summary>
        public ControlType ControlType
        {
            get { return Control.Current.ControlType; }
        }

        /// <summary>
        /// Gets a string containing the class name of a control. 
        /// </summary>
        public string ClassName
        {
            get { return Control.Current.ClassName; }
        }

        /// <summary>
        /// Gets the coordinates of the rectangle that completely encloses the control.
        /// </summary>
        public Rect BoundingRectangle
        {
            get { return Control.Current.BoundingRectangle; }
        }

        /// <summary>
        /// Indicates whether the current control is visible on the screen. 
        /// </summary>
        public bool IsOffscreen
        {
            get { return Control.Current.IsOffscreen; }
        }

        /// <summary>
        /// Indicates whether the current control is visible on the screen. 
        /// </summary>
        public bool IsVisible
        {
            get { return !Control.Current.IsPassword; }
        }

        /// <summary>
        /// Gets the description of the item status of the control. 
        /// </summary>
        public string ItemStatus
        {
            get { return Control.Current.ItemStatus; }
        }

        /// <summary>
        /// Gets the help text associated with the control. 
        /// </summary>
        public string HelpText
        {
            get { return Control.Current.HelpText; }
        }

        /// <summary>
        /// Gets the clickable point for this control. 
        /// </summary>
        public Point ClickablePoint
        {
            get 
            { 
                Point clickablePoint;
                if (Control.TryGetClickablePoint(out clickablePoint))
                {
                    return clickablePoint;
                }
                Rect rect = Control.Current.BoundingRectangle;
                return new Point(rect.TopLeft.X + (rect.Width / 2), rect.TopLeft.Y + (rect.Height / 2));
            }
        }

        #endregion

        #region Control Pattern Properties

        /// <summary>
        /// Gets the dock position for the control. 
        /// If the control does not support the <see cref="DockPattern"/>, a null reference is returned.  
        /// </summary>
        protected DockPosition? DockPosition
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<DockPattern>(Control, DockPattern.Pattern);
                return pattern != null ? (DockPosition?) pattern.Current.DockPosition : null;
            }
        }

        /// <summary>
        /// Gets the current expand/collapse state of the control.
        /// If the control does not support the <see cref="ExpandCollapsePattern"/> , a null reference is returned.
        /// </summary>
        protected ExpandCollapseState? ExpandCollapseState
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<ExpandCollapsePattern>(Control, ExpandCollapsePattern.Pattern);
                return pattern != null ? (ExpandCollapseState?) pattern.Current.ExpandCollapseState : null;
            }
        }

        /// <summary>
        /// Gets the current toggle state of the control.
        /// If the control does not support the <see cref="ToggleState"/> , a null reference is returned.
        /// </summary>
        protected ToggleState? ToggleState
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<TogglePattern>(Control, TogglePattern.Pattern);
                return pattern != null ? (ToggleState?) pattern.Current.ToggleState : null;
            }
        }

        /// <summary>
        /// Gets a value which indicates the primary direction of traversal for a table type control.
        /// If the control does not support the <see cref="TablePattern"/> , a null reference is returned.
        /// </summary>
        protected RowOrColumnMajor? RowOrColumnMajor
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<TablePattern>(Control, TablePattern.Pattern);
                return pattern != null ? (RowOrColumnMajor?) pattern.Current.RowOrColumnMajor : null;
            }
        }

        /// <summary>
        /// Gets a the current state of a window control for the purposes of user interaction.
        /// If the control does not support the <see cref="WindowPattern"/>, a null reference is returned. 
        /// </summary>
        protected WindowInteractionState? WindowInteractionState
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<WindowPattern>(Control, WindowPattern.Pattern);
                return pattern != null ? (WindowInteractionState?) pattern.Current.WindowInteractionState : null;
            }
        }

        /// <summary>
        /// Gets the visual state of a window control (i.e. restored, minimized, maximized). 
        /// If the control does not support the <see cref="WindowPattern"/>, a null reference is returned.
        /// </summary>
        protected WindowVisualState? WindowVisualState
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<WindowPattern>(Control, WindowPattern.Pattern);
                return pattern != null ? (WindowVisualState?) pattern.Current.WindowVisualState : null;
            }
        }

        /// <summary>
        /// Specifies the total number of columns in a grid.  
        /// If the control does not support the <see cref="GridPattern"/>, returns -1. 
        /// </summary>
        protected int ColumnCount
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<GridPattern>(Control, GridPattern.Pattern);
                return pattern != null ? pattern.Current.ColumnCount : -1; 
            }
        }

        /// <summary>
        /// Specifies the total number of rows in a grid.  
        /// If the control does not support the <see cref="GridPattern"/>, returns -1. 
        /// </summary>
        protected int RowCount
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<GridPattern>(Control, GridPattern.Pattern);
                return pattern != null ? pattern.Current.RowCount : -1;
            }
        }

        /// <summary>
        /// Specifies the ordinal number of the column that contains a cell or item. 
        /// If the control does not support the <see cref="GridItemPattern"/>, returns -1. 
        /// </summary>
        protected int Column
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<GridItemPattern>(Control, GridItemPattern.Pattern);
                return pattern != null ? pattern.Current.Column : -1;
            }
        }

        /// <summary>
        /// Specifies the number of columns spanned by a cell or item. 
        /// If the control does not support the <see cref="GridItemPattern"/>, returns -1. 
        /// </summary>
        protected int ColumnSpan
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<GridItemPattern>(Control, GridItemPattern.Pattern);
                return pattern != null ? pattern.Current.ColumnSpan : -1;
            }
        }

        /// <summary>
        /// Specifies the ordinal number of the row that contains a cell or item. 
        /// If the control does not support the <see cref="GridItemPattern"/>, returns -1. 
        /// </summary>
        protected int Row
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<GridItemPattern>(Control, GridItemPattern.Pattern);
                return pattern != null ? pattern.Current.Row : -1;
            }
        }

        /// <summary>
        /// Specifies the number of row spanned by a cell or item. 
        /// If the control does not support the <see cref="GridItemPattern"/>, returns -1. 
        /// </summary>
        protected int RowSpan
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<GridItemPattern>(Control, GridItemPattern.Pattern);
                return pattern != null ? pattern.Current.RowSpan : -1;
            }
        }
        
        /// <summary>
        /// Gets the value that is added to or subtracted from a range control value when a large change is made. 
        /// If the control does not support the <see cref="RangeValuePattern"/>, returns NaN.
        /// </summary>
        protected double LargeChange
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<RangeValuePattern>(Control, RangeValuePattern.Pattern);
                return pattern != null ? pattern.Current.LargeChange : double.NaN;
            }
        }

        /// <summary>
        /// Gets the value that is added to or subtracted from a range control value when a large change is made. 
        /// If the control does not support the <see cref="RangeValuePattern"/>, returns NaN.
        /// </summary>
        protected double SmallChange
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<RangeValuePattern>(Control, RangeValuePattern.Pattern);
                return pattern != null ? pattern.Current.SmallChange : double.NaN;
            }
        }

        /// <summary>
        /// Specifies the maximum range value supported by a control.
        /// If the control does not support the <see cref="RangeValuePattern"/>, returns NaN.
        /// </summary>
        protected double Maximum 
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<RangeValuePattern>(Control, RangeValuePattern.Pattern);
                return pattern != null ? pattern.Current.Maximum : double.NaN;
            }
        }

        /// <summary>
        /// Specifies the minimum range value supported by a control.
        /// If the control does not support the <see cref="RangeValuePattern"/>, returns NaN.
        /// </summary>
        protected double Minimum
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<RangeValuePattern>(Control, RangeValuePattern.Pattern);
                return pattern != null ? pattern.Current.Minimum : double.NaN;
            }
        }

        /// <summary>
        /// Specifies the value of the control.
        /// If the control does not support the <see cref="RangeValuePattern"/>, returns NaN. 
        /// </summary>
        protected double RangeValue
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<RangeValuePattern>(Control, RangeValuePattern.Pattern);
                return pattern != null ? pattern.Current.Value : double.NaN;
            }
        }

        /// <summary>
        /// Gets a value which indicates whether the control can scroll horizontally. 
        /// </summary>
        protected bool HorizontallyScrollable
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<ScrollPattern>(Control, ScrollPattern.Pattern);
                return pattern != null && pattern.Current.HorizontallyScrollable;
            }
        }

        /// <summary>
        /// Gets a value which indicates whether the control can scroll horizontally. 
        /// </summary>
        protected bool VerticallyScrollable
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<ScrollPattern>(Control, ScrollPattern.Pattern);
                return pattern != null && pattern.Current.VerticallyScrollable;
            }
        }

        /// <summary>
        /// Gets the value of the horizontal scroll position.
        /// If the control does not support the <see cref="ScrollPattern"/>, returns NaN. 
        /// </summary>
        protected double HorizontalScrollPercent
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<ScrollPattern>(Control, ScrollPattern.Pattern);
                return pattern != null ? pattern.Current.HorizontalScrollPercent : double.NaN;
            }
        }

        /// <summary>
        /// Gets the value of the vertical scroll position.
        /// If the control does not support the <see cref="ScrollPattern"/>, returns NaN.
        /// </summary>
        protected double VerticalScrollPercent
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<ScrollPattern>(Control, ScrollPattern.Pattern);
                return pattern != null ? pattern.Current.VerticalScrollPercent : double.NaN;
            }
        }

        /// <summary>
        /// Gets the value of the horizontal size of the viewable region.
        /// If the control does not support the <see cref="ScrollPattern"/>, returns NaN.
        /// </summary>
        protected double HorizontalViewSize
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<ScrollPattern>(Control, ScrollPattern.Pattern);
                return pattern != null ? pattern.Current.HorizontalViewSize : double.NaN;
            }
        }

        /// <summary>
        /// Gets the value of the vertical size of the viewable region.
        /// If the control does not support the <see cref="ScrollPattern"/>, returns NaN.
        /// </summary>
        protected double VerticalViewSize
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<ScrollPattern>(Control, ScrollPattern.Pattern);
                return pattern != null ? pattern.Current.VerticalViewSize : double.NaN;
            }
        }

        /// <summary>
        /// Gets a value that indicates whether an item is selected. 
        /// </summary>
        protected bool IsSelected
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<SelectionItemPattern>(Control, SelectionItemPattern.Pattern);
                return pattern != null && pattern.Current.IsSelected;
            }
        }

        /// <summary>
        /// Gets a value which indicates if the control allows more than one child element to be selected concurrently. 
        /// </summary>
        protected bool CanSelectMultiple
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<SelectionPattern>(Control, SelectionPattern.Pattern);
                return pattern != null && pattern.Current.CanSelectMultiple;
            }
        }

        /// <summary>
        /// Gets a value which indicates if the control requires at least one child element to be selected. 
        /// </summary>
        protected bool IsSelectionRequired
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<SelectionPattern>(Control, SelectionPattern.Pattern);
                return pattern != null && pattern.Current.IsSelectionRequired;
            }
        }

        /// <summary>
        /// Gets the text range that encloses the main text of a document. 
        /// </summary>
        protected TextPatternRange DocumentRange
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<TextPattern>(Control, TextPattern.Pattern);
                return pattern != null ? pattern.DocumentRange : null;
            }
        }

        /// <summary>
        /// Gets a value that indicates the type of text selection that is supported by the control. 
        /// </summary>
        protected SupportedTextSelection SupportedTextSelection
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<TextPattern>(Control, TextPattern.Pattern);
                return pattern != null ? pattern.SupportedTextSelection : SupportedTextSelection.None;
            }
        }

        /// <summary>
        /// Gets a value which indicates whether the control can be moved. 
        /// </summary>
        protected bool CanMove
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<TransformPattern>(Control, TransformPattern.Pattern);
                return pattern != null && pattern.Current.CanMove;
            }
        }

        /// <summary>
        /// Gets a value which indicates whether the control can be resized. 
        /// </summary>
        protected bool CanResize
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<TransformPattern>(Control, TransformPattern.Pattern);
                return pattern != null && pattern.Current.CanResize;
            }
        }

        /// <summary>
        /// Gets a value which indicates whether the control can be rotated. 
        /// </summary>
        protected bool CanRotate
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<TransformPattern>(Control, TransformPattern.Pattern);
                return pattern != null && pattern.Current.CanRotate;
            }
        }

        /// <summary>
        /// Gets a value which indicates whether the value of a control is read-only. 
        /// </summary>
        protected bool IsReadOnly
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<ValuePattern>(Control, ValuePattern.Pattern);
                return pattern == null || pattern.Current.IsReadOnly;
            }
        }

        /// <summary>
        /// Gets a value which indicates whether the value of a range control is read-only.
        /// </summary>
        protected bool IsRangeReadOnly
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<RangeValuePattern>(Control, RangeValuePattern.Pattern);
                return pattern == null || pattern.Current.IsReadOnly;
            }
        }

        /// <summary>
        /// Gets the value of a control. 
        /// </summary>
        protected string Value
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<ValuePattern>(Control, ValuePattern.Pattern);
                return pattern != null ? pattern.Current.Value : null;
            }
        }

        /// <summary>
        /// Gets a value which indicates whether a window control can be maximized. 
        /// </summary>
        protected bool CanMaximize
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<WindowPattern>(Control, WindowPattern.Pattern);
                return pattern != null ? pattern.Current.CanMaximize : false;
            }
        }

        /// <summary>
        /// Gets a value which indicates whether a window control can be minimized. 
        /// </summary>
        protected bool CanMinimize
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<WindowPattern>(Control, WindowPattern.Pattern);
                return pattern != null ? pattern.Current.CanMinimize : false;
            }
        }

        /// <summary>
        /// Gets a value which indicates whether a window control is modal. 
        /// </summary>
        protected bool IsModal
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<WindowPattern>(Control, WindowPattern.Pattern);
                return pattern != null ? pattern.Current.IsModal : false;
            }
        }

        /// <summary>
        /// Gets a value which indicates whether a window control is the topmost element in z-order. 
        /// </summary>
        protected bool IsTopmost
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<WindowPattern>(Control, WindowPattern.Pattern);
                return pattern != null ? pattern.Current.IsTopmost : false;
            }
        }

        /// <summary>
        /// Gets the current control specific view. 
        /// </summary>
        protected int CurrentView
        {
            get
            {
                var pattern = AutomationElementPatterns.GetPattern<MultipleViewPattern>(Control, MultipleViewPattern.Pattern);
                return pattern != null ? pattern.Current.CurrentView : -1;
            }
        }

        #endregion 

        #region Constructors

        /// <summary>
        /// Initializes a new instance of the <see cref="UIBaseControl"/> class.
        /// </summary>
        /// <param name="locator">The locator used to find the specific control.</param>
        protected UIBaseControl(string locator)
        {
            _searchCriteria = LocatorParser.GetSearchCriteria(locator);
            try
            {
                Initialize(null, _searchCriteria);
            }
            catch (UIControlNotFoundException ex)
            {
                string expression = locator.StartsWith("[") ? locator : String.Format("[{0}]", locator);
                throw new UIControlNotFoundException(String.Format("Could not find '//UIControl{0}'", expression), ex);
            }
        }
        
        /// <summary>
        /// Initializes a new instance of the <see cref="UIBaseControl"/> class.
        /// </summary>
        /// <param name="controlType">The control type of control.</param>
        protected UIBaseControl(ControlType controlType)
        {
            _searchCriteria = new AutomationElementSearchCriteria();
            _searchCriteria.Add(new AutomationElementExactSearchCondition(AutomationElementIdentifiers.ControlTypeProperty, controlType));
            try
            {
                Initialize(null, _searchCriteria);
            }
            catch (UIControlNotFoundException ex)
            {
                string controlName = "UI" + controlType.ProgrammaticName.Split('.')[1];
                throw new UIControlNotFoundException(String.Format("Could not find '//{0}'", controlName), ex);
            }  
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIBaseControl"/> class.
        /// </summary>
        /// <param name="parent">The parent of the control.</param>
        /// <param name="controlType">The control type of control.</param>
        protected UIBaseControl(UIBaseControl parent, ControlType controlType)
        {
            _searchCriteria = new AutomationElementSearchCriteria();
            _searchCriteria.Add(new AutomationElementExactSearchCondition(AutomationElementIdentifiers.ControlTypeProperty, controlType));
            try
            {
                Initialize(parent, _searchCriteria);
            }
            catch (UIControlNotFoundException ex)
            {
                string controlName = "UI" + controlType.ProgrammaticName.Split('.')[1];
                throw new UIControlNotFoundException(String.Format("Could not found '//{0}'", controlName), ex);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIBaseControl"/> class.
        /// </summary>
        /// <param name="parent">The parent of the control.</param>
        /// <param name="locator">The locator used to find the specific control.</param>
        protected UIBaseControl(UIBaseControl parent, string locator)
        {
            _searchCriteria = LocatorParser.GetSearchCriteria(locator);
            try
            {
                Initialize(parent, _searchCriteria);
            }
            catch (UIControlNotFoundException ex)
            {
                string expression = locator.StartsWith("[") ? locator : String.Format("[{0}]", locator);
                throw new UIControlNotFoundException(String.Format("Could not find '//UIControl{0}'", expression), ex);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIBaseControl"/> class.
        /// </summary>
        /// <param name="parent">The parent of the control.</param>
        /// <param name="controlType">The control type of the control.</param>
        /// <param name="locator">The locator used to find the specific control.</param>
        protected UIBaseControl(UIBaseControl parent, ControlType controlType, string locator)
        {
            _searchCriteria = LocatorParser.GetSearchCriteria(locator);
            _searchCriteria.Add(new AutomationElementExactSearchCondition(AutomationElementIdentifiers.ControlTypeProperty, controlType), 0);
            try
            {
                Initialize(parent, _searchCriteria);
            }
            catch (UIControlNotFoundException ex)
            {
                string controlName = "UI" + controlType.ProgrammaticName.Split('.')[1];
                string expression = locator.StartsWith("[") ? locator : String.Format("[{0}]", locator); 
                throw new UIControlNotFoundException(String.Format("Could not find '//{0}{1}'", controlName, expression), ex);
            }
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIBaseControl"/> class.
        /// </summary>
        /// <param name="control">The underlying <see cref="AutomationElement"/> of the control.</param>
        protected UIBaseControl(AutomationElement control)
        {
            _control = control;
            _parentControl = null;
            AutomationElement parentWindow = AutomationElementFinder.GetParentWindow(_control); 
            _parentWindow = parentWindow == null ? null : new UIWindow(parentWindow);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIBaseControl"/> class.
        /// </summary>
        /// <param name="control">The underlying <see cref="AutomationElement"/> of the control.</param>
        /// <param name="controlType">The control type of the control.</param>
        /// <exception cref="ArgumentException">The control type of the control should match the expected control type.</exception>
        protected UIBaseControl(AutomationElement control, ControlType controlType)
        {
            if (control.Current.ControlType != controlType)
            {
                throw new ArgumentException(
                    String.Format("The type '{0}' of the control does not match the expected control type '{1}'",
                                  control.Current.ControlType.ProgrammaticName, controlType.ProgrammaticName));
            }
            _control = control;
            _parentControl = null;
            var parentWindow = AutomationElementFinder.GetParentWindow(_control);
            _parentWindow = parentWindow == null ? null : new UIWindow(parentWindow);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIBaseControl"/> class.
        /// </summary>
        /// <param name="parent">The parent of the control</param>
        /// <param name="control">The underlying <see cref="AutomationElement"/> of the control.</param>
        protected UIBaseControl(UIBaseControl parent, AutomationElement control)
        {
            _control = control;
            _parentControl = parent;
            var parentWindow = AutomationElementFinder.GetParentWindow(_control);
            _parentWindow = parentWindow == null ? null : new UIWindow(parentWindow);
        }

        /// <summary>
        /// Initializes a new instance of the <see cref="UIBaseControl"/> class.
        /// </summary>
        /// <param name="parent">The parent of the control</param>
        /// <param name="control">The underlying <see cref="AutomationElement"/> of the control.</param>
        /// <param name="controlType">The control type of the control.</param>
        /// <exception cref="ArgumentException">The control type of the control should match the expected control type.</exception>
        protected UIBaseControl(UIBaseControl parent, AutomationElement control, ControlType controlType)
        {
            if (control.Current.ControlType != controlType)
            {
                throw new ArgumentException(
                    String.Format("The type '{0}' of the control does not match the expected control type '{1}'",
                                  control.Current.ControlType.ProgrammaticName, controlType.ProgrammaticName));
            }
            _control = control;
            _parentControl = parent;
            var parentWindow = AutomationElementFinder.GetParentWindow(_control);
            _parentWindow = parentWindow == null ? null : new UIWindow(parentWindow);
        }

        /// <summary>
        /// Initializes common attributes for a new <see cref="UIBaseControl"/>. 
        /// </summary>
        /// <param name="parent">The parent of the control.</param>
        /// <param name="searchCriteria">The search criteria for the control.</param>
        private void Initialize(UIBaseControl parent, IAutomationElementSearchCriteria searchCriteria)
        {
            _parentControl = parent;
            var parentElement = parent == null ? AutomationElement.RootElement : parent.Control;
            _control = AutomationElementFinder.FindFirst(parentElement, searchCriteria, AutomationConfiguration.Current.ObjectSearchTime);
            if (_control == null)
            {
                throw new UIControlNotFoundException(String.Format("No control found for criteria: " + searchCriteria));
            }
            
            var parentWindow = AutomationElementFinder.GetParentWindow(_control);
            _parentWindow = parentWindow == null ? null : new UIWindow(parentWindow);
        }

        #endregion 

        /// <summary>
        /// Sets keyboard focus to the current control. 
        /// </summary>
        /// <exception cref="ElementNotAvailableException">The element is no longer available.</exception>
        public void SetFocus()
        {
            WaitForParentWindowToBeReady();
            _control.SetFocus(); 
        }

        /// <summary>
        /// Clicks on the control.
        /// </summary>
        /// <exception cref="NoClickablePointException">The element has no available clickable point.</exception>
        /// <exception cref="ElementNotAvailableException">The element is no longer available.</exception>
        public void Click()
        {
            WaitForParentWindowToBeReady();
            Point clickablePoint = Control.GetClickablePoint();
            Mouse.Click(Mouse.MouseButton.Left, clickablePoint.X, clickablePoint.Y); 
            WaitForParentWindowToBeReady();
        }

        /// <summary>
        /// Double clicks on the control.
        /// </summary>
        /// <exception cref="NoClickablePointException">The element has no available clickable point.</exception>
        /// <exception cref="ElementNotAvailableException">The element is no longer available.</exception>
        public void DoubleClick()
        {
            WaitForParentWindowToBeReady();
            Point clickablePoint = Control.GetClickablePoint();
            Mouse.DoubleClick(clickablePoint.X, clickablePoint.Y); 
            WaitForParentWindowToBeReady();
        }

        /// <summary>
        /// Moves the mouse cursor the control's clickable point to hover over the control. 
        /// </summary>
        /// <exception cref="NoClickablePointException">The element has no available clickable point.</exception>
        /// <exception cref="ElementNotAvailableException">The element is no longer available.</exception>
        public void MouseHover()
        {
            WaitForParentWindowToBeReady();
            Point clickablePoint = Control.GetClickablePoint(); 
            Mouse.Move(clickablePoint.X, clickablePoint.Y);
            WaitForParentWindowToBeReady();
        }

        /// <summary>
        /// Presses the mouse button down on the control's clickable point. 
        /// </summary>
        /// <param name="mouseButton">The mouse button to press down.</param>
        public void MousePress(Mouse.MouseButton mouseButton)
        {
            WaitForParentWindowToBeReady();
            Point clickablePoint = Control.GetClickablePoint();
            Mouse.Move(clickablePoint.X, clickablePoint.Y);
            Mouse.ButtonDown(mouseButton);
            WaitForParentWindowToBeReady(); 
        }

        /// <summary>
        /// Presses the mouse button down on the control's clickable point. 
        /// </summary>
        /// <param name="mouseButton">The mouse button to press down.</param>
        public void MouseRelease(Mouse.MouseButton mouseButton)
        {
            WaitForParentWindowToBeReady();
            Point clickablePoint = Control.GetClickablePoint();
            Mouse.Move(clickablePoint.X, clickablePoint.Y);
            Mouse.ButtonUp(mouseButton);
            WaitForParentWindowToBeReady();
        }

        /// <summary>
        /// Types the text into the current control.
        /// </summary>
        /// <param name="text">The text to type.</param>
        public void TypeText(string text)
        {
            WaitForParentWindowToBeReady(); 
            Keyboard.TypeText(text);
            WaitForParentWindowToBeReady(); 
        }
        
        /// <summary>
        /// Tries to open a context menu on the current control.
        /// </summary>
        public void OpenContextMenu()
        {
            WaitForParentWindowToBeReady();
            var point = ClickablePoint; 
            Mouse.Click(Mouse.MouseButton.Right, point.X, point.Y);
            WaitForParentWindowToBeReady();
        }

        /// <summary>
        /// Waits for the parent window of this control to be ready. 
        /// </summary>
        public void WaitForParentWindowToBeReady()
        {
            if (_parentWindow != null)
            {
                _parentWindow.WaitUntilReady(AutomationConfiguration.Current.WindowWaitTime);
            }
        }

        /// <summary>
        /// Waits for the parent window of this control to be ready. 
        /// </summary>
        /// <param name="milliseconds">The maximum time, in milliseconds, to wait for the parent window to become ready.</param>
        public void WaitForParentWindowToBeReady(int milliseconds)
        {
            if (_parentWindow != null)
            {
                _parentWindow.WaitUntilReady(milliseconds);
            }
        }

        #region Control Patterns

        /// <summary>
        /// Sets the dock position of the control.
        /// </summary>
        /// <param name="dockPosition">The new dock position.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Dock(DockPosition dockPosition)
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.Dock(Control, dockPosition);
        }

        /// <summary>
        /// Expands the current element, displaying all its child nodes, controls or content. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Expand()
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.Expand(Control);
        }

        /// <summary>
        /// Collapses the current element, hiding all its child nodes, controls or content. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Collapse()
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.Collapse(Control);
        }

        /// <summary>
        /// Calls invoke a control to initiate or perform a single, unambiguous action that does not maintain state when activated.
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Invoke()
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.Invoke(Control);
        }

        /// <summary>
        /// Retrieves an element that represents the specified cell in a table or grid control. 
        /// </summary>
        /// <param name="row">The ordinal number of the row of interest.</param>
        /// <param name="col">The ordinal number of the column of interest.</param>
        /// <returns>The <see cref="AutomationElement"/> that represents the retrieved cell.</returns>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        /// <remarks>Grid coordinates are zero-based with the upper left (or upper right cell depending on locale) having coordinates (0,0).</remarks>
        protected AutomationElement GetItem(int row, int col)
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetItem(Control, row, col);
        }

        /// <summary>
        /// Retrieves a collection of integer values that identify the views available for a control.
        /// </summary>
        /// <returns>A collection of view identifiers. An empty collection is returned if there are no found view identifiers.</returns>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected int[] GetSupportedViews()
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetSupportedViews(Control); 
        }

        /// <summary>
        /// Gets the name of a control specific view. 
        /// </summary>
        /// <param name="viewId">A view identifier.</param>
        /// <returns>The localized name of the view.</returns>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected string GetViewName(int viewId)
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetViewName(Control, viewId); 
        }
        
        /// <summary>
        /// Sets the current control specific view. 
        /// </summary>
        /// <param name="viewId">The view identifier to set.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void SetCurrentView(int viewId)
        {
            WaitForParentWindowToBeReady();
            var pattern = (MultipleViewPattern) Control.GetCurrentPattern(MultipleViewPattern.Pattern); 
            pattern.SetCurrentView(viewId);
        }

        /// <summary>
        /// Scrolls the visible region of the content area horizontally and vertically. 
        /// </summary>
        /// <param name="horizontalAmount">The horizontal scrolling increment that is specific to the control.</param>
        /// <param name="verticalAmount">The vertical scrolling increment that is specific to the control.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        /// <remarks>No scroll should be passed if if the control cannot be scrolled in a given direction.</remarks>
        protected void Scroll(ScrollAmount horizontalAmount, ScrollAmount verticalAmount)
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.Scroll(Control, horizontalAmount, verticalAmount);
        }

        /// <summary>
        /// Scrolls the visble region of the content area vertically by a <see cref="ScrollAmount"/>.
        /// </summary>
        /// <param name="amount">The vertical scrolling increment.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void ScrollVertically(ScrollAmount amount)
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.ScrollVertical(Control, amount);
        }

        /// <summary>
        /// Scrolls the visble region of the content area horizontally by a <see cref="ScrollAmount"/>.
        /// </summary>
        /// <param name="amount">The horizontal scrolling increment.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void ScrollHorizontally(ScrollAmount amount)
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.ScrollHorizontally(Control, amount);
        }

        /// <summary>
        /// Sets the horizontal and vertical scroll position as a percentage of the total content area within the control. 
        /// </summary>
        /// <param name="horizontalPercent">
        /// The percentage of the total horizontal content area. 
        /// <see cref="ScrollPattern.NoScroll"/> should be passed in if the control cannot be scrolled in this direction.
        /// </param>
        /// <param name="verticalPercent">
        /// The percentage of the total vertical content area. 
        /// <see cref="ScrollPattern.NoScroll"/> should be passed in if the control cannot be scrolled in this direction.
        /// </param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void SetScrollPercent(double horizontalPercent, double verticalPercent)
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.SetScrollPercent(Control, horizontalPercent, verticalPercent);
        }

        /// <summary>
        /// Sets the scroll percentage to the top of the control.  
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void ScrollToTop()
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.ScrollToTop(Control);
        }

        /// <summary>
        /// Scrolls the content area of a container object in order to display the element within the visible region (viewport) of the container.
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void ScrollIntoView()
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.ScrollIntoView(Control);
        }

        /// <summary>
        /// Deselects any selected items and then selects the current element.
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Select()
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.Select(Control);
        }

        /// <summary>
        /// Adds the current element to the collection of selected items. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void AddToSelection()
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.AddToSelection(Control);
        }

        /// <summary>
        /// Removes the current element to the collection of selected items. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void RemoveFromSelection()
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.RemoveFromSelection(Control);
        }

        /// <summary>
        /// Gets a collection of elements that represents the current selection for an element.
        /// </summary>
        /// <returns>A collection of selected elements.</returns>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected AutomationElement[] GetSelection()
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetSelection(Control);
        }

        /// <summary>
        /// Gets the parent selection container of a control. 
        /// </summary>
        /// <returns>The <see cref="AutomationElement"/> of the parent control that implements the <see cref="SelectionPattern"/>.</returns>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected AutomationElement GetSelectionContainer()
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetSelectionContainer(Control); 
        }

        /// <summary>
        /// Gets a collection of elements that represents all the column headers in a table.
        /// </summary>
        /// <returns>A collection of elements representing the column headers.</returns>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected AutomationElement[] GetColumnHeaders()
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetColumnHeaders(Control); 
        }

        /// <summary>
        /// Gets a collection of elements that represents all the row headers in a table.
        /// </summary>
        /// <returns>A collection of elements representing the row headers.</returns>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected AutomationElement[] GetRowHeaders()
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetRowHeaders(Control);
        }

        /// <summary>
        /// Gets a collection of column headers associated with a table item or cell. 
        /// </summary>
        /// <returns>A collection of elements representing the column headers.</returns>
        /// <exception cref="InvalidOperationException">The pattern is not supported by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected AutomationElement[] GetColumnHeaderItems()
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetColumnHeaderItems(Control);
        }

        /// <summary>
        /// Gets a collection of row headers associated with a table item or cell. 
        /// </summary>
        /// <returns>A collection of elements representing the column headers.</returns>
        /// <exception cref="InvalidOperationException">The pattern is not supported by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected AutomationElement[] GetRowHeaderItems()
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetRowHeaderItems(Control); 
        }

        /// <summary>
        /// Gets the container of a cell or item. 
        /// </summary>
        /// <returns>An <see cref="AutomationElement"/> that represents the container of a cell or item.</returns>
        /// <exception cref="InvalidOperationException">The pattern is not supported by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected AutomationElement GetContainingGrid()
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetContainingGrid(Control); 
        }

        /// <summary>
        /// Retrieves a collection of text ranges that represents the currently selected text in a text-based control.
        /// </summary>
        /// <returns>A collection of disjoint text ranges.</returns>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected TextPatternRange[] GetTextSelection()
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetTextSelection(Control);
        }

        /// <summary>
        /// Retrieves an array of disjoint text ranges from a text-based control where each text range represents a contiguous span of visible text.
        /// </summary>
        /// <returns>The collection of visible text ranges within the container or an empty array.</returns>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected TextPatternRange[] GetVisibleRanges()
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.GetVisibleRanges(Control);
        }

        /// <summary>
        /// Retrieves a text range enclosing a child element such as an image, hyperlink, Microsoft Excel spreadsheet, or other embedded object. 
        /// </summary>
        /// <returns>A range that spans the child element.</returns>
        /// <exception cref="ArgumentNullException">The child element is null.</exception>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected TextPatternRange RangeFromChild(AutomationElement childElement)
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.RangeFromChild(Control, childElement);
        }

        /// <summary>
        /// Returns the degenerate (empty) text range nearest to the specified screen coordinates. 
        /// </summary>
        /// <param name="screenLocation">The location in screen coordinates.</param>
        /// <returns>A degenerate range nearest the specified location. Null is never returned.</returns>
        /// <exception cref="ArgumentException">The given point is outside the <see cref="AutomationElement"/> associated with the text pattern.</exception>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected TextPatternRange RangeFromPoint(Point screenLocation)
        {
            WaitForParentWindowToBeReady();
            return AutomationElementPatterns.RangeFromPoint(Control, screenLocation);
        }

        /// <summary>
        /// Toggles the current control. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        /// <remarks>A control will cycle through its <see cref="ToggleState"/> in this order: On, Off and, if supported, Indeterminate.</remarks>
        protected void Toggle()
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.Toggle(Control);
        }

        /// <summary>
        /// Toggles on the current control. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void ToggleOn()
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.ToggleOn(Control);
        }

        /// <summary>
        /// Toggles off the current control. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void ToggleOff()
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.ToggleOff(Control);
        }

        /// <summary>
        /// Moves a control. 
        /// </summary>
        /// <param name="x">Absolute screen coordinates of the left side of the control.</param>
        /// <param name="y">Absolute screen coordinates of the top of the control.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Move(double x, double y)
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.Move(Control, x, y);
        }

        /// <summary>
        /// Resizes a control. 
        /// </summary>
        /// <param name="width">The new width of the window, in pixels.</param>
        /// <param name="height">The new height of the window, in pixels.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Resize(double width, double height)
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.Resize(Control, width, height);
        }

        /// <summary>
        /// Rotates a control. 
        /// </summary>
        /// <param name="degrees">The number of degrees to rotate the control. A positive number rotates clockwise; a negative number rotates counterclockwise.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Rotate(double degrees)
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.Rotate(Control, degrees);
        }

        /// <summary>
        /// Inserts a string into a control that supports the value pattern. 
        /// </summary>
        /// <param name="value">The string to be inserted.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void SetValue(string value)
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.SetValue(Control, value);
        }

        /// <summary>
        /// Sets the value for a range control.
        /// </summary>
        /// <param name="value">The value to set.</param>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void SetRangeValue(double value)
        {
            WaitForParentWindowToBeReady();
            AutomationElementPatterns.SetRangeValue(Control, value);
        }

        /// <summary>
        /// Closes a window type control. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The control pattern cannot be performed by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Close()
        {
            AutomationElementPatterns.Close(Control); 
        }

        /// <summary>
        /// Maximizes the specified window. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The pattern is not supported by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Maximize()
        {
            AutomationElementPatterns.Maximize(Control); 
        }

        /// <summary>
        /// Minimizes the specified window. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The pattern is not supported by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Minimize()
        {
            AutomationElementPatterns.Minimize(Control); 
        }

        /// <summary>
        /// Restores the specified window to its normal state. 
        /// </summary>
        /// <exception cref="InvalidOperationException">The pattern is not supported by the element.</exception>
        /// <exception cref="ElementNotAvailableException">The element is not available anymore.</exception>
        protected void Restore()
        {
            AutomationElementPatterns.Restore(Control); 
        }

        #endregion

        #region Controls

        /// <summary>
        /// Helper method for getting a collection of descendants.
        /// </summary>
        /// <typeparam name="T">The type of control to retrieve.</typeparam>
        /// <param name="controlType">The type of control to find.</param>
        /// <returns>A collection of controls. An empty collection is returned if there are no matching controls found.</returns>
        private List<T> UIControls<T>(ControlType controlType) where T : UIBaseControl
        {
            List<AutomationElement> elements = AutomationElementFinder.FindAllDescendantsOfType(Control, controlType);
            var controls = new List<T>(elements.Count);
            controls.AddRange(elements.Select(element => ControlFactory.GetUIControl(element, controlType) as T));
            return controls;
        }

        /// <summary>
        /// Helper method for getting a collection of descendants.
        /// </summary>
        /// <typeparam name="T">The type of control to retrieve.</typeparam>
        /// <param name="controlType">The type of control to find.</param>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of controls. An empty collection is returned if there are no matching controls found.</returns>
        private List<T> UIControls<T>(ControlType controlType, string locator) where T : UIBaseControl
        {
            var searchCriteria = LocatorParser.GetSearchCriteria(locator);
            searchCriteria.Add(new AutomationElementExactSearchCondition(AutomationElement.ControlTypeProperty, controlType));
            List<AutomationElement> elements = AutomationElementFinder.FindAll(Control, searchCriteria);
            var controls = new List<T>(elements.Count);
            controls.AddRange(elements.Select(element => ControlFactory.GetUIControl(element, controlType) as T));
            return controls;
        }

        /// <summary>
        /// Gets a descendant button type element.
        /// </summary>
        /// <returns>A descendant button element.</returns>
        public UIButton UIButton()
        {
            return new UIButton(this);
        }

        /// <summary>
        /// Gets a descendant button type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant button element.</returns>
        public UIButton UIButton(string locator)
        {
            return new UIButton(this, locator);
        }

        /// <summary>
        /// Gets all the descendant button type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of button elements.</returns>
        public List<UIButton> UIButtons(string locator)
        {
            return UIControls<UIButton>(ControlType.Button, locator);
        }

        /// <summary>
        /// Gets all the descendant button type elements. 
        /// </summary>
        /// <returns>A collection of button elements.</returns>
        public List<UIButton> UIButtons()
        {
            return UIControls<UIButton>(ControlType.Button);
        }

        /// <summary>
        /// Gets a descendant calendar type element.
        /// </summary>
        /// <returns>A descendant calendar element.</returns>
        public UICalendar UICalendar()
        {
            return new UICalendar(this);
        }

        /// <summary>
        /// Gets a descendant calendar type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant calendar element.</returns>
        public UICalendar UICalendar(string locator)
        {
            return new UICalendar(this, locator);
        }

        /// <summary>
        /// Gets all the descendant calendar type elements. 
        /// </summary>
        /// <returns>A collection of calendar elements.</returns>
        public List<UICalendar> UICalendars()
        {
            return UIControls<UICalendar>(ControlType.Calendar);
        }

        /// <summary>
        /// Gets all the descendant calendar type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of calendar elements.</returns>
        public List<UICalendar> UICalendars(string locator)
        {
            return UIControls<UICalendar>(ControlType.Calendar, locator);
        }

        /// <summary>
        /// Gets a descendant check box type element.
        /// </summary>
        /// <returns>A descendant check box element.</returns>
        public UICheckBox UICheckBox()
        {
            return new UICheckBox(this);
        }

        /// <summary>
        /// Gets a descendant check box type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant checkbox element.</returns>
        public UICheckBox UICheckBox(string locator)
        {
            return new UICheckBox(this, locator);
        }

        /// <summary>
        /// Gets all the descendant check box type elements. 
        /// </summary>
        /// <returns>A collection of check box elements.</returns>
        public List<UICheckBox> UICheckBoxes()
        {
            return UIControls<UICheckBox>(ControlType.CheckBox);
        }

        /// <summary>
        /// Gets all the descendant check box type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of check box elements.</returns>
        public List<UICheckBox> UICheckBoxes(string locator)
        {
            return UIControls<UICheckBox>(ControlType.CheckBox, locator);
        }

        /// <summary>
        /// Gets a descendant combo box type element.
        /// </summary>
        /// <returns>A descendant combo box element.</returns>
        public UIComboBox UIComboBox()
        {
            return new UIComboBox(this);
        }

        /// <summary>
        ///Gets a descendant combo box type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant combo box element.</returns>
        public UIComboBox UIComboBox(string locator)
        {
            return new UIComboBox(this, locator);
        }

        /// <summary>
        /// Gets all the descendant combo box type elements. 
        /// </summary>
        /// <returns>A collection of combo box elements.</returns>
        public List<UIComboBox> UIComboBoxes()
        {
            return UIControls<UIComboBox>(ControlType.ComboBox);
        }

        /// <summary>
        /// Gets all the descendant combo box type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of combo box elements.</returns>
        public List<UIComboBox> UIComboBoxes(string locator)
        {
            return UIControls<UIComboBox>(ControlType.ComboBox, locator);
        }

        /// <summary>
        /// Gets a descendant generic control type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant generic control element.</returns>
        public UIControl UIControl(string locator)
        {
            return new UIControl(this, locator);
        }

        /// <summary>
        /// Gets a descendant custom control type element.
        /// </summary>
        /// <returns>A descendant custom element.</returns>
        public UICustom UICustom()
        {
            return new UICustom(this);
        }

        /// <summary>
        /// Gets a descendant custom control type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant custom element.</returns>
        public UICustom UICustom(string locator)
        {
            return new UICustom(this, locator);
        }

        /// <summary>
        /// Gets all the descendant custom type elements. 
        /// </summary>
        /// <returns>A collection of custom elements.</returns>
        public List<UICustom> UICustoms()
        {
            return UIControls<UICustom>(ControlType.Custom);
        }

        /// <summary>
        /// Gets all the descendant custom type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of custom elements.</returns>
        public List<UICustom> UICustoms(string locator)
        {
            return UIControls<UICustom>(ControlType.Custom, locator);
        }

        /// <summary>
        /// Gets a descendant data grid type element.
        /// </summary>
        /// <returns>A descendant data grid element.</returns>
        public UIDataGrid UIDataGrid()
        {
            return new UIDataGrid(this);
        }

        /// <summary>
        /// Gets a descendant data grid type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant data grid element.</returns>
        public UIDataGrid UIDataGrid(string locator)
        {
            return new UIDataGrid(this, locator);
        }

        /// <summary>
        /// Gets all the descendant data grid type elements. 
        /// </summary>
        /// <returns>A collection of data grid elements.</returns>
        public List<UIDataGrid> UIDataGrids()
        {
            return UIControls<UIDataGrid>(ControlType.DataGrid);
        }

        /// <summary>
        /// Gets all the descendant data grid type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of data grid elements.</returns>
        public List<UIDataGrid> UIDataGrids(string locator)
        {
            return UIControls<UIDataGrid>(ControlType.DataGrid, locator);
        }

        /// <summary>
        /// Gets a descendant data item type element.
        /// </summary>
        /// <returns>A descendant data item element.</returns>
        public UIDataItem UIDataItem()
        {
            return new UIDataItem(this);
        }

        /// <summary>
        /// Gets a descendant data item type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant data item element.</returns>
        public UIDataItem UIDataItem(string locator)
        {
            return new UIDataItem(this, locator);
        }

        /// <summary>
        /// Gets all the descendant data item type elements. 
        /// </summary>
        /// <returns>A collection of data item elements.</returns>
        public List<UIDataItem> UIDataItems()
        {
            return UIControls<UIDataItem>(ControlType.DataItem);
        }

        /// <summary>
        /// Gets all the descendant data item type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of data item elements.</returns>
        public List<UIDataItem> UIDataItems(string locator)
        {
            return UIControls<UIDataItem>(ControlType.DataItem, locator);
        }

        /// <summary>
        /// Gets a descendant document type element.
        /// </summary>
        /// <returns>A descendant document element.</returns>
        public UIDocument UIDocument()
        {
            return new UIDocument(this);
        }

        /// <summary>
        /// Gets a descendant document type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant document element.</returns>
        public UIDocument UIDocument(string locator)
        {
            return new UIDocument(this, locator);
        }

        /// <summary>
        /// Gets all the descendant check box type elements. 
        /// </summary>
        /// <returns>A collection of check box elements.</returns>
        public List<UIDocument> UIDocuments()
        {
            return UIControls<UIDocument>(ControlType.Document);
        }

        /// <summary>
        /// Gets all the descendant check box type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of check box elements.</returns>
        public List<UIDocument> UIDocuments(string locator)
        {
            return UIControls<UIDocument>(ControlType.Document, locator);
        }

        /// <summary>
        /// Gets a descendant edit type element.
        /// </summary>
        /// <returns>A descendant edit element.</returns>
        public UIEdit UIEdit()
        {
            return new UIEdit(this);
        }

        /// <summary>
        /// Gets a descendant edit type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant edit element.</returns>
        public UIEdit UIEdit(string locator)
        {
            return new UIEdit(this, locator);
        }

        /// <summary>
        /// Gets all the descendant edit type control elements. 
        /// </summary>
        /// <returns>A collection of edit control elements.</returns>
        public List<UIEdit> UIEdits()
        {
            return UIControls<UIEdit>(ControlType.Edit);
        }

        /// <summary>
        /// Gets all the descendant edit type control elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of edit control elements.</returns>
        public List<UIEdit> UIEdits(string locator)
        {
            return UIControls<UIEdit>(ControlType.Edit, locator);
        }

        /// <summary>
        /// Gets a descendant group type element.
        /// </summary>
        /// <returns>A descendant group element.</returns>
        public UIGroup UIGroup()
        {
            return new UIGroup(this);
        }

        /// <summary>
        /// Gets a descendant group type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant group element.</returns>
        public UIGroup UIGroup(string locator)
        {
            return new UIGroup(this, locator);
        }

        /// <summary>
        /// Gets all the descendant group type elements. 
        /// </summary>
        /// <returns>A collection of group elements.</returns>
        public List<UIGroup> UIGroups()
        {
            return UIControls<UIGroup>(ControlType.Group);
        }

        /// <summary>
        /// Gets all the descendant group type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of group elements.</returns>
        public List<UIGroup> UIGroups(string locator)
        {
            return UIControls<UIGroup>(ControlType.Group, locator);
        }

        /// <summary>
        /// Gets a descendant header type element.
        /// </summary>
        /// <returns>A descendant header element.</returns>
        public UIHeader UIHeader()
        {
            return new UIHeader(this);
        }

        /// <summary>
        /// Gets a descendant header type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant header element.</returns>
        public UIHeader UIHeader(string locator)
        {
            return new UIHeader(this, locator);
        }

        /// <summary>
        /// Gets all the descendant header type elements. 
        /// </summary>
        /// <returns>A collection of header elements.</returns>
        public List<UIHeader> UIHeaders()
        {
            return UIControls<UIHeader>(ControlType.Header);
        }

        /// <summary>
        /// Gets all the descendant header type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of header elements.</returns>
        public List<UIHeader> UIHeaders(string locator)
        {
            return UIControls<UIHeader>(ControlType.Header, locator);
        }

        /// <summary>
        /// Gets a descendant header item type element.
        /// </summary>
        /// <returns>A descendant header item element.</returns>
        public UIHeaderItem UIHeaderItem()
        {
            return new UIHeaderItem(this);
        }

        /// <summary>
        /// Gets a descendant header item type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant header item element.</returns>
        public UIHeaderItem UIHeaderItem(string locator)
        {
            return new UIHeaderItem(this, locator);
        }

        /// <summary>
        /// Gets all the descendant header item type elements. 
        /// </summary>
        /// <returns>A collection of header item elements.</returns>
        public List<UIHeaderItem> UIHeaderItems()
        {
            return UIControls<UIHeaderItem>(ControlType.HeaderItem);
        }

        /// <summary>
        /// Gets all the descendant header item type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of header item elements.</returns>
        public List<UIHeaderItem> UIHeaderItems(string locator)
        {
            return UIControls<UIHeaderItem>(ControlType.HeaderItem, locator);
        }

        /// <summary>
        /// Gets a descendant hyperlink type element.
        /// </summary>
        /// <returns>A descendant hyperlink element.</returns>
        public UIHyperlink UIHyperlink()
        {
            return new UIHyperlink(this);
        }

        /// <summary>
        /// Gets a descendant hyperlink type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant hyperlink element.</returns>
        public UIHyperlink UIHyperlink(string locator)
        {
            return new UIHyperlink(this, locator);
        }

        /// <summary>
        /// Gets all the descendant hyperlink type elements. 
        /// </summary>
        /// <returns>A collection of hyperlink elements.</returns>
        public List<UIHyperlink> UIHyperlinks()
        {
            return UIControls<UIHyperlink>(ControlType.Hyperlink);
        }

        /// <summary>
        /// Gets all the descendant hyperlink type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of hyperlink elements.</returns>
        public List<UIHyperlink> UIHyperlinks(string locator)
        {
            return UIControls<UIHyperlink>(ControlType.Hyperlink, locator);
        }

        /// <summary>
        /// Gets a descendant image type element.
        /// </summary>
        /// <returns>A descendant image element.</returns>
        public UIImage UIImage()
        {
            return new UIImage(this);
        }

        /// <summary>
        /// Gets a descendant image type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant image element.</returns>
        public UIImage UIImage(string locator)
        {
            return new UIImage(this, locator);
        }

        /// <summary>
        /// Gets all the descendant image type elements. 
        /// </summary>
        /// <returns>A collection of image elements.</returns>
        public List<UIImage> UIImages()
        {
            return UIControls<UIImage>(ControlType.Image);
        }

        /// <summary>
        /// Gets all the descendant image type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of image elements.</returns>
        public List<UIImage> UIImages(string locator)
        {
            return UIControls<UIImage>(ControlType.Image, locator);
        }

        /// <summary>
        /// Gets a descendant list type element.
        /// </summary>
        /// <returns>A descendant list element.</returns>
        public UIList UIList()
        {
            return new UIList(this);
        }

        /// <summary>
        /// Gets a descendant list type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant list element.</returns>
        public UIList UIList(string locator)
        {
            return new UIList(this, locator);
        }

        /// <summary>
        /// Gets all the descendant list type elements. 
        /// </summary>
        /// <returns>A collection of list elements.</returns>
        public List<UIList> UILists()
        {
            return UIControls<UIList>(ControlType.List);
        }

        /// <summary>
        /// Gets all the descendant list type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of list elements.</returns>
        public List<UIList> UILists(string locator)
        {
            return UIControls<UIList>(ControlType.List, locator);
        }

        /// <summary>
        /// Gets a descendant list item type element.
        /// </summary>
        /// <returns>A descendant list item element.</returns>
        public UIListItem UIListItem()
        {
            return new UIListItem(this);
        }

        /// <summary>
        /// Gets a descendant list item type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant list item element.</returns>
        public UIListItem UIListItem(string locator)
        {
            return new UIListItem(this, locator);
        }

        /// <summary>
        /// Gets all the descendant list item type elements. 
        /// </summary>
        /// <returns>A collection of list item elements.</returns>
        public List<UIListItem> UIListItems()
        {
            return UIControls<UIListItem>(ControlType.ListItem);
        }

        /// <summary>
        /// Gets all the descendant list item type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of list item elements.</returns>
        public List<UIListItem> UIListItems(string locator)
        {
            return UIControls<UIListItem>(ControlType.ListItem, locator);
        }

        /// <summary>
        /// Gets a descendant menu type element.
        /// </summary>
        /// <returns>A descendant menu element.</returns>
        public UIMenu UIMenu()
        {
            return new UIMenu(this);
        }

        /// <summary>
        /// Gets a descendant menu type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant menu element.</returns>
        public UIMenu UIMenu(string locator)
        {
            return new UIMenu(this, locator);
        }

        /// <summary>
        /// Gets all the descendant menu type elements. 
        /// </summary>
        /// <returns>A collection of menu elements.</returns>
        public List<UIMenu> UIMenus()
        {
            return UIControls<UIMenu>(ControlType.Menu);
        }

        /// <summary>
        /// Gets all the descendant menu type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of menu elements.</returns>
        public List<UIMenu> UIMenus(string locator)
        {
            return UIControls<UIMenu>(ControlType.Menu, locator);
        }

        /// <summary>
        /// Gets a descendant menu item type element.
        /// </summary>
        /// <returns>A descendant menu item element.</returns>
        public UIMenuItem UIMenuItem()
        {
            return new UIMenuItem(this);
        }

        /// <summary>
        /// Gets a descendant menu item type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant menu item element.</returns>
        public UIMenuItem UIMenuItem(string locator)
        {
            return new UIMenuItem(this, locator);
        }

        /// <summary>
        /// Gets all the descendant menu item type elements. 
        /// </summary>
        /// <returns>A collection of menu item elements.</returns>
        public List<UIMenuItem> UIMenuItems()
        {
            return UIControls<UIMenuItem>(ControlType.MenuItem);
        }

        /// <summary>
        /// Gets all the descendant menu item type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of menu item elements.</returns>
        public List<UIMenuItem> UIMenuItems(string locator)
        {
            return UIControls<UIMenuItem>(ControlType.MenuItem, locator);
        }

        /// <summary>
        /// Gets a descendant menu bar type element.
        /// </summary>
        /// <returns>A descendant menu bar element.</returns>
        public UIMenuBar UIMenuBar()
        {
            return new UIMenuBar(this);
        }

        /// <summary>
        /// Gets a descendant menu bar type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant menu bar element.</returns>
        public UIMenuBar UIMenuBar(string locator)
        {
            return new UIMenuBar(this, locator);
        }

        /// <summary>
        /// Gets all the descendant menu bar type elements. 
        /// </summary>
        /// <returns>A collection of menu bar elements.</returns>
        public List<UIMenuBar> UIMenuBars()
        {
            return UIControls<UIMenuBar>(ControlType.MenuBar);
        }

        /// <summary>
        /// Gets all the descendant menu bar type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of menu bar elements.</returns>
        public List<UIMenuBar> UIMenuBars(string locator)
        {
            return UIControls<UIMenuBar>(ControlType.MenuBar, locator);
        }

        /// <summary>
        /// Gets a descendant pane type element.
        /// </summary>
        /// <returns>A descendant pane element.</returns>
        public UIPane UIPane()
        {
            return new UIPane(this);
        }

        /// <summary>
        /// Gets a descendant pane type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant pane element.</returns>
        public UIPane UIPane(string locator)
        {
            return new UIPane(this, locator);
        }

        /// <summary>
        /// Gets all the descendant pane type elements. 
        /// </summary>
        /// <returns>A collection of pane elements.</returns>
        public List<UIPane> UIPanes()
        {
            return UIControls<UIPane>(ControlType.Pane);
        }

        /// <summary>
        /// Gets all the descendant pane type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of pane elements.</returns>
        public List<UIPane> UIPanes(string locator)
        {
            return UIControls<UIPane>(ControlType.Pane, locator);
        }

        /// <summary>
        /// Gets a descendant progress bar type element.
        /// </summary>
        /// <returns>A descendant progress bar element.</returns>
        public UIProgressBar UIProgressBar()
        {
            return new UIProgressBar(this);
        }

        /// <summary>
        /// Gets a descendant progress bar type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant progress bar element.</returns>
        public UIProgressBar UIProgressBar(string locator)
        {
            return new UIProgressBar(this, locator);
        }

        /// <summary>
        /// Gets all the descendant progress bar type elements. 
        /// </summary>
        /// <returns>A collection of progress bar elements.</returns>
        public List<UIProgressBar> UIProgressBars()
        {
            return UIControls<UIProgressBar>(ControlType.ProgressBar);
        }

        /// <summary>
        /// Gets all the descendant progress bar type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of progress bar elements.</returns>
        public List<UIProgressBar> UIProgressBars(string locator)
        {
            return UIControls<UIProgressBar>(ControlType.ProgressBar, locator);
        }

        /// <summary>
        /// Gets a descendant radio button type element.
        /// </summary>
        /// <returns>A descendant radio button element.</returns>
        public UIRadioButton UIRadioButton()
        {
            return new UIRadioButton(this);
        }

        /// <summary>
        /// Gets a descendant radio button type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant radio button element.</returns>
        public UIRadioButton UIRadioButton(string locator)
        {
            return new UIRadioButton(this, locator);
        }

        /// <summary>
        /// Gets all the descendant radio button type elements. 
        /// </summary>
        /// <returns>A collection of radio button elements.</returns>
        public List<UIRadioButton> UIRadioButtons()
        {
            return UIControls<UIRadioButton>(ControlType.RadioButton);
        }

        /// <summary>
        /// Gets all the descendant radio button type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of radio button elements.</returns>
        public List<UIRadioButton> UIRadioButtons(string locator)
        {
            return UIControls<UIRadioButton>(ControlType.RadioButton, locator);
        }

        /// <summary>
        /// Gets a descendant scrollbar type element.
        /// </summary>
        /// <returns>A descendant scrollbar element.</returns>
        public UIScrollBar UIScrollBar()
        {
            return new UIScrollBar(this);
        }

        /// <summary>
        /// Gets a descendant scrollbar type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant scrollbar element.</returns>
        public UIScrollBar UIScrollBar(string locator)
        {
            return new UIScrollBar(this, locator);
        }

        /// <summary>
        /// Gets all the descendant scrollbar type elements. 
        /// </summary>
        /// <returns>A collection of scrollbar elements.</returns>
        public List<UIScrollBar> UIScrollBars()
        {
            return UIControls<UIScrollBar>(ControlType.ScrollBar);
        }

        /// <summary>
        /// Gets all the descendant scrollbar type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of scrollbar elements.</returns>
        public List<UIScrollBar> UIScrollBars(string locator)
        {
            return UIControls<UIScrollBar>(ControlType.ScrollBar, locator);
        }

        /// <summary>
        /// Gets a descendant separator type element.
        /// </summary>
        /// <returns>A descendant separator element.</returns>
        public UISeparator UISeparator()
        {
            return new UISeparator(this);
        }

        /// <summary>
        /// Gets a descendant separator type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant separator element.</returns>
        public UISeparator UISeparator(string locator)
        {
            return new UISeparator(this, locator);
        }

        /// <summary>
        /// Gets all the descendant separator type elements. 
        /// </summary>
        /// <returns>A collection of separator elements.</returns>
        public List<UISeparator> UISeparators()
        {
            return UIControls<UISeparator>(ControlType.Separator);
        }

        /// <summary>
        /// Gets all the descendant separator type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of separator elements.</returns>
        public List<UISeparator> UISeparators(string locator)
        {
            return UIControls<UISeparator>(ControlType.Separator, locator);
        }

        /// <summary>
        /// Gets a descendant slider type element.
        /// </summary>
        /// <returns>A descendant slider element.</returns>
        public UISlider UISlider()
        {
            return new UISlider(this);
        }

        /// <summary>
        /// Gets a descendant slider type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant slider element.</returns>
        public UISlider UISlider(string locator)
        {
            return new UISlider(this, locator);
        }

        /// <summary>
        /// Gets all the descendant hyperlink type elements. 
        /// </summary>
        /// <returns>A collection of hyperlink elements.</returns>
        public List<UISlider> UISliders()
        {
            return UIControls<UISlider>(ControlType.Slider);
        }

        /// <summary>
        /// Gets all the descendant hyperlink type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of hyperlink elements.</returns>
        public List<UISlider> UISliders(string locator)
        {
            return UIControls<UISlider>(ControlType.Slider, locator);
        }

        /// <summary>
        /// Gets a descendant spinner type element.
        /// </summary>
        /// <returns>A descendant spinner element.</returns>
        public UISpinner UISpinner()
        {
            return new UISpinner(this);
        }

        /// <summary>
        ///  Gets a descendant spinner type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant spinner element.</returns>
        public UISpinner UISpinner(string locator)
        {
            return new UISpinner(this, locator);
        }

        /// <summary>
        /// Gets all the descendant spinner type elements. 
        /// </summary>
        /// <returns>A collection of spinner elements.</returns>
        public List<UISpinner> UISpinners()
        {
            return UIControls<UISpinner>(ControlType.Spinner);
        }

        /// <summary>
        /// Gets all the descendant spinner type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of spinner elements.</returns>
        public List<UISpinner> UISpinners(string locator)
        {
            return UIControls<UISpinner>(ControlType.Spinner, locator);
        }

        /// <summary>
        ///  Gets a descendant split button type element.
        /// </summary>
        /// <returns>A descendant split button element.</returns>
        public UISplitButton UISplitButton()
        {
            return new UISplitButton(this);
        }

        /// <summary>
        /// Gets a descendant split button type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant split button element.</returns>
        public UISplitButton UISplitButton(string locator)
        {
            return new UISplitButton(this, locator);
        }

        /// <summary>
        /// Gets all the descendant split button type elements. 
        /// </summary>
        /// <returns>A collection of split button elements.</returns>
        public List<UISplitButton> UISplitButtons()
        {
            return UIControls<UISplitButton>(ControlType.SplitButton);
        }

        /// <summary>
        /// Gets all the descendant split button type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of split button elements.</returns>
        public List<UISplitButton> UISplitButtons(string locator)
        {
            return UIControls<UISplitButton>(ControlType.SplitButton, locator);
        }

        /// <summary>
        /// Gets a descendant status bar type element.
        /// </summary>
        /// <returns>A descendant split button element.</returns>
        public UIStatusBar UIStatusBar()
        {
            return new UIStatusBar(this);
        }

        /// <summary>
        /// Gets a descendant status bar type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant status bar element.</returns>
        public UIStatusBar UIStatusBar(string locator)
        {
            return new UIStatusBar(this, locator);
        }

        /// <summary>
        /// Gets all the descendant status bars type elements. 
        /// </summary>
        /// <returns>A collection of status bars elements.</returns>
        public List<UIStatusBar> UIStatusBars()
        {
            return UIControls<UIStatusBar>(ControlType.StatusBar);
        }

        /// <summary>
        /// Gets all the descendant status bars type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of status bars elements.</returns>
        public List<UIStatusBar> UIStatusBars(string locator)
        {
            return UIControls<UIStatusBar>(ControlType.StatusBar, locator);
        }

        /// <summary>
        ///  Gets a descendant tab type element.
        /// </summary>
        /// <returns>A descendant tab element.</returns>
        public UITab UITab()
        {
            return new UITab(this);
        }

        /// <summary>
        ///  Gets a descendant tab type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant tab element.</returns>
        public UITab UITab(string locator)
        {
            return new UITab(this, locator);
        }

        /// <summary>
        /// Gets all the descendant tab type elements. 
        /// </summary>
        /// <returns>A collection of tab elements.</returns>
        public List<UITab> UITabs()
        {
            return UIControls<UITab>(ControlType.Tab);
        }

        /// <summary>
        /// Gets all the descendant tab type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of tab elements.</returns>
        public List<UITab> UITabs(string locator)
        {
            return UIControls<UITab>(ControlType.Tab, locator);
        }

        /// <summary>
        ///  Gets a descendant tab item type element.
        /// </summary>
        /// <returns>A descendant tab item element.</returns>
        public UITabItem UITabItem()
        {
            return new UITabItem(this);
        }

        /// <summary>
        /// Gets a descendant tab item type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant tab item element.</returns>
        public UITabItem UITabItem(string locator)
        {
            return new UITabItem(this, locator);
        }

        /// <summary>
        /// Gets all the descendant hyperlink type elements. 
        /// </summary>
        /// <returns>A collection of hyperlink elements.</returns>
        public List<UITabItem> UITabItems()
        {
            return UIControls<UITabItem>(ControlType.TabItem);
        }

        /// <summary>
        /// Gets all the descendant hyperlink type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of hyperlink elements.</returns>
        public List<UITabItem> UITabItems(string locator)
        {
            return UIControls<UITabItem>(ControlType.TabItem, locator);
        }

        /// <summary>
        /// Gets a descendant table type element.
        /// </summary>
        /// <returns>A descendant table element.</returns>
        public UITable UITable()
        {
            return new UITable(this);
        }

        /// <summary>
        /// Gets a descendant table type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant table element.</returns>
        public UITable UITable(string locator)
        {
            return new UITable(this, locator);
        }

        /// <summary>
        /// Gets all the descendant table type elements. 
        /// </summary>
        /// <returns>A collection of table elements.</returns>
        public List<UITable> UITables()
        {
            return UIControls<UITable>(ControlType.Table);
        }

        /// <summary>
        /// Gets all the descendant table type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of table elements.</returns>
        public List<UITable> UITables(string locator)
        {
            return UIControls<UITable>(ControlType.Table, locator);
        }

        /// <summary>
        /// Gets a descendant text type element.
        /// </summary>
        /// <returns>A descendant text element.</returns>
        public UIText UIText()
        {
            return new UIText(this);
        }

        /// <summary>
        ///  Gets a descendant text type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant text element.</returns>
        public UIText UIText(string locator)
        {
            return new UIText(this, locator);
        }

        /// <summary>
        /// Gets all the descendant text type elements. 
        /// </summary>
        /// <returns>A collection of text elements.</returns>
        public List<UIText> UITexts()
        {
            return UIControls<UIText>(ControlType.Text);
        }

        /// <summary>
        /// Gets all the descendant text type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of text elements.</returns>
        public List<UIText> UITexts(string locator)
        {
            return UIControls<UIText>(ControlType.Text, locator);
        }

        /// <summary>
        /// Gets a descendant thumb type element.
        /// </summary>
        /// <returns>A descendant thumb element.</returns>
        public UIThumb UIThumb()
        {
            return new UIThumb(this);
        }

        /// <summary>
        /// Gets a descendant thumb type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant thumb element.</returns>
        public UIThumb UIThumb(string locator)
        {
            return new UIThumb(this, locator);
        }

        /// <summary>
        /// Gets all the descendant thumb type elements. 
        /// </summary>
        /// <returns>A collection of thumb elements.</returns>
        public List<UIThumb> UIThumbs()
        {
            return UIControls<UIThumb>(ControlType.Thumb);
        }

        /// <summary>
        /// Gets all the descendant thumb type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of thumb elements.</returns>
        public List<UIThumb> UIThumbs(string locator)
        {
            return UIControls<UIThumb>(ControlType.Thumb, locator);
        }

        /// <summary>
        /// Gets a descendant titlebar type element.
        /// </summary>
        /// <returns>A descendant titlebar element.</returns>
        public UITitleBar UITitleBar()
        {
            return new UITitleBar(this);
        }

        /// <summary>
        /// Gets a descendant titlebar type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant titlebar element.</returns>
        public UITitleBar UITitleBar(string locator)
        {
            return new UITitleBar(this, locator);
        }

        /// <summary>
        /// Gets all the descendant titlebar type elements. 
        /// </summary>
        /// <returns>A collection of titlebar elements.</returns>
        public List<UITitleBar> UITitleBars()
        {
            return UIControls<UITitleBar>(ControlType.TitleBar);
        }

        /// <summary>
        /// Gets all the descendant titlebar type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of titlebar elements.</returns>
        public List<UITitleBar> UITitleBars(string locator)
        {
            return UIControls<UITitleBar>(ControlType.TitleBar, locator);
        }

        /// <summary>
        /// Gets a descendant toolbar type element.
        /// </summary>
        /// <returns>A descendant toolbar element.</returns>
        public UIToolBar UIToolBar()
        {
            return new UIToolBar(this);
        }

        /// <summary>
        /// Gets a descendant toolbar type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant toolbar element.</returns>
        public UIToolBar UIToolBar(string locator)
        {
            return new UIToolBar(this, locator);
        }

        /// <summary>
        /// Gets all the descendant toolbar type elements. 
        /// </summary>
        /// <returns>A collection of toolbar elements.</returns>
        public List<UIToolBar> UIToolBars()
        {
            return UIControls<UIToolBar>(ControlType.ToolBar);
        }

        /// <summary>
        /// Gets all the descendant toolbar type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of toolbar elements.</returns>
        public List<UIToolBar> UIToolBars(string locator)
        {
            return UIControls<UIToolBar>(ControlType.ToolBar, locator);
        }

        /// <summary>
        /// Gets a descendant tooltip type element.
        /// <returns>A descendant tooltip element.</returns>
        /// </summary>
        public UIToolTip UIToolTip()
        {
            return new UIToolTip(this);
        }

        /// <summary>
        /// Gets a descendant tooltip type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant tooltip element.</returns>
        public UIToolTip UIToolTip(string locator)
        {
            return new UIToolTip(this, locator);
        }

        /// <summary>
        /// Gets all the descendant tooltip type elements. 
        /// </summary>
        /// <returns>A collection of toolti[ elements.</returns>
        public List<UIToolTip> UIToolTips()
        {
            return UIControls<UIToolTip>(ControlType.ToolTip);
        }

        /// <summary>
        /// Gets all the descendant tooltip type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of toolti[ elements.</returns>
        public List<UIToolTip> UIToolTips(string locator)
        {
            return UIControls<UIToolTip>(ControlType.ToolTip, locator);
        }

        /// <summary>
        /// Gets a descendant tree type element.
        /// </summary>
        /// <returns>A descendant tree element.</returns>
        public UITree UITree()
        {
            return new UITree(this);
        }

        /// <summary>
        /// Gets a descendant tree type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant tree element.</returns>
        public UITree UITree(string locator)
        {
            return new UITree(this, locator);
        }

        /// <summary>
        /// Gets all the descendant tree type elements. 
        /// </summary>
        /// <returns>A collection of tree elements.</returns>
        public List<UITree> UITrees()
        {
            return UIControls<UITree>(ControlType.Tree);
        }

        /// <summary>
        /// Gets all the descendant tree type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of tree elements.</returns>
        public List<UITree> UITrees(string locator)
        {
            return UIControls<UITree>(ControlType.Tree, locator);
        }

        /// <summary>
        /// Gets a descendant tree item type element.
        /// </summary>
        /// <returns>A descendant tree item element.</returns>
        public UITreeItem UITreeItem()
        {
            return new UITreeItem(this);
        }

        /// <summary>
        /// Gets a descendant tree item type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant tree item element.</returns>
        public UITreeItem UITreeItem(string locator)
        {
            return new UITreeItem(this, locator);
        }

        /// <summary>
        /// Gets all the descendant tree item type elements. 
        /// </summary>
        /// <returns>A collection of tree item elements.</returns>
        public List<UITreeItem> UITreeItems()
        {
            return UIControls<UITreeItem>(ControlType.TreeItem);
        }

        /// <summary>
        /// Gets all the descendant tree item type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of tree item elements.</returns>
        public List<UITreeItem> UITreeItems(string locator)
        {
            return UIControls<UITreeItem>(ControlType.TreeItem, locator);
        }

        /// <summary>
        /// Gets a descendant window type element.
        /// </summary>
        /// <returns>A descendant window element.</returns>
        public UIWindow UIWindow()
        {
            return new UIWindow(this);
        }

        /// <summary>
        /// Gets a descendant window type element.
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A descendant window element.</returns>
        public UIWindow UIWindow(string locator)
        {
            return new UIWindow(this, locator);
        }

        /// <summary>
        /// Gets all the descendant window type elements. 
        /// </summary>
        /// <returns>A collection of window elements.</returns>
        public List<UIWindow> UIWindows()
        {
            return UIControls<UIWindow>(ControlType.Window);
        }

        /// <summary>
        /// Gets all the descendant window type elements. 
        /// </summary>
        /// <param name="locator">The locator for this control.</param>
        /// <returns>A collection of window elements.</returns>
        public List<UIWindow> UIWindows(string locator)
        {
            return UIControls<UIWindow>(ControlType.Window, locator);
        }

        #endregion
    }
}
